#pragma once
#include "../ProgAdmin/AppObject.h"
#include <vector>
using namespace std;

#define  _TERM(Ter) static_cast<Term::const_reference>(Ter)
#define  _TYPE(Ty)  static_cast<Type::const_reference>(Ty)

class Token : public AppObject{

public:
	typedef Token* pointer;
	typedef Token& reference;
	typedef const Token& const_reference;
	typedef pointer iterator;
	typedef AppObjectException exception;

protected:
	string SyntacticSugar;

public:
	bool hasSyntax( ) const;
	void setSyntax(string);
	const string& getSyntax() const;


public:
	Token(const string& = "");
	Token(const_reference To);
	virtual ~Token();
	
public:
//Pure Abstract
	virtual bool isTerm() const=0;
	virtual bool isType() const=0;
	virtual Token::pointer applyArgument(Token::const_reference)  const=0;
	virtual Token::pointer clone() const=0;
	virtual bool operator==(Token::const_reference) const;

public:
//Overidable
	virtual string toString() const;
	virtual string view() const;
	virtual Token::pointer replaceAll(Token::const_reference, Token::const_reference) const;
	virtual size_t complexity( ) const {return 1;};
};


//Assignable
class TokenPair : public pair<Token::pointer, Token::pointer>{

public:
	typedef const TokenPair& const_reference;

protected:
	void destroy();
	void copy(const TokenPair&);

public:
	TokenPair(Token::const_reference, Token::const_reference);
	TokenPair(const TokenPair&);
	~TokenPair();

public:
	TokenPair::const_reference operator=(TokenPair::const_reference);
	bool operator==(TokenPair::const_reference) const;
	
public:
	Token::const_reference getRight() const{return (*this->second);};
	Token::const_reference getLeft() const{return (*this->first);};
		
public:
	//From Token
	TokenPair* replaceAll(Token::const_reference, Token::const_reference) const;
	TokenPair* clone() const;
	string toString() const;
	size_t complexity() const {return getLeft().complexity()+getRight().complexity();}

public:
	virtual Token* replaceAllOccurencesOfFirstInSecondBy(Token::const_reference) const;
	virtual Token* replaceAllOccurencesOfArgumentBySecondInFirst(Token::const_reference) const;
	};



class TokenVector : public vector<Token::pointer>{
//owns its elements
public:

	TokenVector(Token::const_reference);
	TokenVector(vector<Token *>);
	TokenVector(const TokenVector&);
	~TokenVector( );

public:
	void push_back(Token::const_reference);
	Token::const_reference operator[ ] (size_t) const;


public:
	TokenVector* replaceAll(Token::const_reference, Token::const_reference) const;
	TokenVector* clone( ) const;
	string toString() const;
	size_t complexity() const;
	
	
};


















